package fr.emse.tatiana.video;

import java.awt.Component;
import java.awt.Frame;
import java.awt.Panel;
import java.io.File;
import java.util.LinkedList;
import java.util.List;

import org.apache.xmlrpc.XmlRpcException;
import org.eclipse.core.runtime.Path;
import org.eclipse.swt.SWT;
import org.eclipse.swt.awt.SWT_AWT;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.ui.PlatformUI;

import quicktime.QTException;
import quicktime.QTSession;
import quicktime.app.view.QTFactory;
import quicktime.io.OpenMovieFile;
import quicktime.io.QTFile;
import quicktime.std.StdQTException;
import quicktime.std.clocks.TimeRecord;
import quicktime.std.movies.Movie;

import fr.emse.tatiana.replayable.ContinuousReplayable;
import fr.emse.tatiana.replayable.SynchronisationEvent;
import fr.emse.tatiana.replayable.ExternalReplayable;

public class VideoController implements ContinuousReplayable,
		ExternalReplayable {
	
	private Shell shell;
	private Frame f;
	private Panel pane;
	private Component component;
	// QT movie 
	Movie movie=null;
	
	// visual debug
//	JLabel gotoLabel;
//	JLabel sLabel;
//	JLabel eLabel;
//	JLabel dLabel;
//	JLabel newTimeLabel;
//	JLabel qtTimeLabel;
//	JLabel qtErrorLabel;
//	JLabel inRangeLabel;
	
	
	// info passed on from description of the video in the corpus
	long startTime; 
	long endTime;
	long delta;
	float qtDelta;
	
	// tells if video is playing
	boolean isPlaying = false;
	// records playback speed
	int speed=1;
	// tells if timewise we are in between the start and the end of the video
	boolean inRange = false;
	// tells if tatiana is in play mode
	boolean isTatianaPlaying = false;
	
	float volume;
	
	boolean mute = false;
	
	
	public VideoController(long firsttime, long lasttime, long delta) {
		startTime = firsttime;
		endTime = lasttime;
		this.delta = delta;

		PlatformUI.getWorkbench().getDisplay().syncExec(new Runnable() {
			public void run() {
			}
		});
	}

	public void initGUI() {
		shell = new Shell(PlatformUI.getWorkbench().getDisplay(),SWT.EMBEDDED | SWT.MODELESS | SWT.TITLE | SWT.RESIZE );
		f = SWT_AWT.new_Frame(shell);
	    pane = new Panel();
	    pane.setLayout(new java.awt.BorderLayout());
//	    sLabel = new JLabel("s:"+startTime);
//	    eLabel = new JLabel("e:"+endTime);
//	    dLabel = new JLabel("d:"+delta);
//	    gotoLabel = new JLabel("goto:");
//	    newTimeLabel = new JLabel("nt:");
//	    qtTimeLabel = new JLabel("qt:");
//	    qtErrorLabel = new JLabel("qtE:");
//	    inRangeLabel = new JLabel("ir:");
//	    Panel northPanel = new Panel();
//	    Panel southPanel = new Panel();
//	    northPanel.setLayout(new java.awt.FlowLayout());
//	    southPanel.setLayout(new java.awt.FlowLayout());
//	    northPanel.add(sLabel);
//	    northPanel.add(eLabel);
//	    northPanel.add(dLabel);
//	    northPanel.add(qtErrorLabel);
//	    southPanel.add(gotoLabel);
//	    southPanel.add(newTimeLabel);
//	    southPanel.add(qtTimeLabel);
//	    southPanel.add(inRangeLabel);
//	    pane.add(northPanel,java.awt.BorderLayout.NORTH);
//	    pane.add(southPanel,java.awt.BorderLayout.SOUTH);
	}
	
	public List<Long> getEvents() {
		List<Long> l=new LinkedList<Long>();
		l.add(startTime+delta);
		l.add(endTime+delta);
		return l;

	}

	public void pause() {
		isTatianaPlaying = false;
		setState();

	}

	public void play() {
		isTatianaPlaying = true;
		setState();
	}

	public void setSpeed(int newSpeed) {try {
		// if playing set movie playback rate
		if(isPlaying) {
			movie.setRate(newSpeed); // setRate enables playback if not already playing
		} 
		// update internal speed (so when play is pressed playback is at correct speed)
		speed = newSpeed;
		
	} catch (StdQTException e) {
		// do nothing
		e.printStackTrace();
	}
	}

	public void end() {
		try {
			movie.stop();
			pane.remove(component);
		} catch (StdQTException e) {
			// do nothing
			e.printStackTrace();
		} catch (QTException e) {
			// do nothing
			e.printStackTrace();
		}
		shell.close();

	}

	public void goTo(SynchronisationEvent extract) {
		
		if (extract.getNow()==null) {
			return;
		}
		
		long time = extract.getNow();
		//pane.add(new JLabel("goto: "+time));
		//gotoLabel.setText("goto:"+time);
		long replayertime = time-delta;
		// check if we are in range or not
		if( replayertime>=startTime && replayertime<=endTime ) {
			// set in range to true
			//inRangeLabel.setText("ir:true");
			if (!inRange) {		
				inRange = true;
				// check if anything needs doing (starting the video for example)
				setState();
			}
			long newTime=time-delta-startTime;
			newTime = (long) (newTime*qtDelta);
			System.err.println("VID"+newTime);
			// set video to correct timestamp
//			newTimeLabel.setText("nt:"+newTime);
//			try {
//				qtTimeLabel.setText("qtT:"+movie.getTime()+" qtTC:"+movie.getTimeScale()+" /:"+movie.getTime()/movie.getTimeScale()+"qtD:"+movie.getDuration());
//			} catch (StdQTException e1) {
//				//  Auto-generated catch block
//				e1.printStackTrace();
//			}
			try {
				int i = movie.getTimeScale();	
				System.err.println("movieTimescale:"+i);
				movie.setTime(new TimeRecord(movie.getTimeScale(),newTime));
				//movie.setTime(new TimeRecord(movie.getTimeScale(),newTime));
			} catch (StdQTException e) {
				// do nothing
				e.printStackTrace();
			} catch (QTException e) {
				// do nothing
				//qtErrorLabel.setText("qtE2:"+e);
				e.printStackTrace();
			}
		} else {
			//inRangeLabel.setText("ir:false");
			inRange = false;
			setState();
		}
	}

	public void mark(long time) {

	}

	public void openFile(String filename) throws XmlRpcException {
		//pane.add(new JLabel("open: "+filename));
		// get file handle
		File file = new File(filename);
		//File file = new File("D:\\steven\\avi2.avi");
		
		// get Quicktime file handle
		QTFile qtFile = new QTFile(file);
		// start QT Session
		try {
			QTSession.open(); // doesn't show up in most tutorials but is vitally important!
		} catch (QTException e4) {
			// do nothing
			System.err.println("[QTController] connot init QTSession");
			e4.printStackTrace();
		    QTSession.close ();
		}
		
		//Open QT File for Reading
		OpenMovieFile omFile=null;
		try {
			omFile = OpenMovieFile.asRead(qtFile);
		} catch (QTException e3) {
			// do nothing
			e3.printStackTrace();
		}
		// get movie object from video file
		try {
			movie = Movie.fromFile(omFile);
		} catch (QTException e3) {
			// do nothing
			e3.printStackTrace();
		}
		
		// make a java component from movie object
        component=null;
		try {
			component = (Component)QTFactory.makeQTComponent (movie);
		} catch (QTException e2) {
			// do nothing
			e2.printStackTrace();
		}
		
		// init window
		initGUI();
		
        
        // get video height/width to resize frame later
        int width=0;
        int height=0;
		try {
			width = movie.getNaturalBoundsRect().getWidth();
	        height = movie.getNaturalBoundsRect().getWidth();
			volume = movie.getVolume();
			if (mute) {
				movie.setVolume(0);				
			}
		} catch (StdQTException e) {
			// do nothing 
			e.printStackTrace();
		}
		
		// init different varibles for playback
		isPlaying = false;
		inRange = false;
		isTatianaPlaying = false;
		speed = 1;
		
		if( endTime != startTime ) {
			try {
				qtDelta = ((float)movie.getDuration())/((float)(endTime-startTime));
			} catch (StdQTException e) {
				// do nothing
				e.printStackTrace();
			}
		} else {
			System.err.println("[QT Video Controller]: start time and end time are identical");
		}
		// check if video needs playing
		setState();
		
		// add component to pane
        pane.add(component,java.awt.BorderLayout.CENTER);
		
		// resize and show pane
		pane.setSize(width, height);
	    f.add(pane);
        f.pack();
        shell.setSize(f.getWidth(),f.getHeight());
        shell.setText(new Path(filename).lastSegment());
        shell.open();
		
	}
	// plays/stops/changes rate of movie depending on time
	// called by play/pause/setSpeed methods
	public void setState() {
		// if we're in range, tatiana is playing and we're not yet playing the video: start playback
		if (inRange && isTatianaPlaying && !isPlaying) {
			isPlaying = true;
			try {
				movie.setRate(speed); // starts playback at current speed
			} catch (StdQTException e) {
				// do nothing
				e.printStackTrace();
			}
		}else if (inRange && (isTatianaPlaying ^ isPlaying)) {
			isPlaying = isTatianaPlaying;
			try {
				movie.stop();
			} catch (StdQTException e) {
				// do nothing
				e.printStackTrace();
			}
		} else if (!inRange && isPlaying) { // if out of range : stop playback
			isPlaying = false;
			try {
				movie.stop();
			} catch (StdQTException e) {
				// do nothing
				e.printStackTrace();
			}
		}
	}
	
	public void setMute(boolean m) {
		mute = m;
		
		try {
			if (movie!=null) {
				movie.setVolume(mute?0:volume);
			}
		} catch (StdQTException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
			
	}

}
